/*
 * Copyright (C) 2009 Teleca Poland Sp. z o.o. <android@teleca.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.sylar.happyreader.view;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.RejectedExecutionException;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.ListView;

import com.sylar.happyreader.BookApplication;
import com.sylar.happyreader.tools.ImageCache;

/**
 * ImageView extended class allowing easy downloading
 * of remote images
 * 
 * @author hws
 */
public  class RemoteImageView extends ImageView{
	
	/**
	 * 尝试请求的次数
	 * Maximum number of unsuccesful tries of downloading an image
	 */
	private static int MAX_FAILURES = 3;

	public RemoteImageView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}

	public RemoteImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public RemoteImageView(Context context) {
		super(context);
		init();
	}

	/**
	 * Sharable code between constructors
	 */
	private void init(){
	}
	
	/**
	 * 远程图片地址
	 * Remote image location
	 */
	private String mUrl;
	
	/**
	 * 当前获取图片成功的url
	 * Currently successfully grabbed url
	 */
	private String mCurrentlyGrabbedUrl;
	
	/**
	 * 失败请求的次数
	 * Remote image download failure counter
	 */
	private int mFailure;  

	/**
	 * 图片在listView中的位置
	 * Position of the image in the mListView
	 */
	private int mPosition;

	/**
	 * ListView containg this image
	 */
	private ListView mListView;
	
	/**
	 * Default image shown while loading or on url not found
	 */
	private Integer mDefaultImage;

	
	public void setImageUrl(String url){
		
		if(mListView == null && mCurrentlyGrabbedUrl != null && mCurrentlyGrabbedUrl.equals(url)){
			// do nothing image is grabbed & loaded, we are golden
			return;
		}
		
		if(mUrl != null && mUrl.equals(url)){
			mFailure++;
			if(mFailure > MAX_FAILURES){
				loadDefaultImage();
				return;
			}
		} else {
			mUrl = url;
			mFailure = 0; 
		}

		ImageCache imageCache = BookApplication.getInstance().getImageCache();
		
		/**
		 * 如果缓存中存在 则直接从缓存中加载
		 */
		if(imageCache.isCached(url)){  
			this.setImageBitmap(imageCache.get(url));
		}
		/**
		 * 若缓存中不存在，则进行异步加载
		 */
		else {
			try{
				new DownloadTask().execute(url);
			} catch (RejectedExecutionException e) {
				// do nothing, just don't crash
			}
		}
	}
	
	public void setDefaultImage(Integer resid){
		mDefaultImage = resid;
	}
	
	private void loadDefaultImage(){
		if(mDefaultImage != null)
			setImageResource(mDefaultImage);
	}
	
	public void setImageUrl(String url, int position, ListView listView){
		mPosition = position;
		mListView = listView;
		setImageUrl(url);
	}

	/**
	 * Asynchronous image download task
	 * 
	 * @author Lukasz Wisniewski
	 */
	/**
	 * AsyncTask定义了三种泛型类型 Params，Progress和Result。
	 * 
	 *   Params 启动任务执行的输入参数，比如HTTP请求的URL。
	 *   Progress 后台任务执行的百分比。
	 *   Result 后台执行任务最终返回的结果，比如String。
 	 * 使用AsyncTask类，以下是几条必须遵守的准则：
 	 *   Task的实例必须在UI thread中创建；
 	 *   execute方法必须在UI thread中调用；
 	 *   不要手动的调用onPreExecute(), 
 	 *      onPostExecute(Result)，
 	 *      doInBackground(Params...), 
 	 *      onProgressUpdate(Progress...)这几个方法；
 	 *   该task只能被执行一次，否则多次调用时将会出现异常；      
	 */
	class DownloadTask extends AsyncTask<String, Void, String>{
		
		private String mTaskUrl;
       
		/**
		 * 这里是最终用户调用Excute时的接口，当任务执行之前开始调用此方法，可以在这里显示进度对话框。
		 */
		@Override
		public void onPreExecute() {
			loadDefaultImage();
			super.onPreExecute();
		}
       
		/**
		 * Params 启动任务执行的输入参数，比如HTTP请求的URL。
		 * doInBackground(Params…) 后台执行，比较耗时的操作都可以放在这里      注意这里不能直接操作UI。
		 * 此方法在后台线程执行，完成任务的主要工作，通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
		 * 
		 */
		@Override
		public String doInBackground(String... params) {

			mTaskUrl = params[0];
			InputStream stream = null;
			URL imageUrl;
			Bitmap bmp = null;

			try {
				imageUrl = new URL(mTaskUrl);
				try {
					stream = imageUrl.openStream();
					bmp = BitmapFactory.decodeStream(stream);
					try {
						if(bmp != null){
							//将从网络加载到的图片放到缓存中
							BookApplication.getInstance().getImageCache().put(mTaskUrl, bmp,true);
							
						} else {
							//TODO
						}
					} catch (NullPointerException e) {
						e.printStackTrace();
					}
				} catch (IOException e) {
					e.printStackTrace();
				} finally {
					try {
						if(stream != null){
							stream.close();
						}
					} catch (IOException e) {}
				}

			} catch (MalformedURLException e) {
				e.printStackTrace();
			}
			return mTaskUrl;
		}

		/**
		 * onPostExecute(Result)  相当于Handler 处理UI的方式
		 * 在这里面可以使用在doInBackground 得到的结果处理操作UI。
		 * 此方法在主线程执行，任务执行的结果作为此方法的参数返回
		 */
		@Override
		public void onPostExecute(String url) {
			super.onPostExecute(url);
			
			// target url may change while loading
			if(!mTaskUrl.equals(mUrl))
				return;
			//从缓存中取出在doInBackground(String... params)方法从网络加载到的图片
			Bitmap bmp = BookApplication.getInstance().getImageCache().get(url);
			if(bmp == null){
				
				RemoteImageView.this.setImageUrl(url);
			} else {
				
				//如果图像从属于某一记录表更新它只有当它的可见
				if(mListView != null)
					if(mPosition < mListView.getFirstVisiblePosition() || mPosition > mListView.getLastVisiblePosition())
						return;
				
				RemoteImageView.this.setImageBitmap(bmp);
				mCurrentlyGrabbedUrl = url;
			}
		}
		
		/**
		 * 可以使用进度条增加用户体验度。 此方法在主线程执行，用于显示任务执行的进度。
		 */
		@Override
		protected void onProgressUpdate(Void... values) {
			// TODO Auto-generated method stub
			super.onProgressUpdate(values);
		}

	};

}
